#include "../include/statusServe_rpc.h"
#include "../include/conf_reader.h"
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/random_generator.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/uuid/uuid_io.hpp>
#include "../include/redis_pool.h"


#define CHAT_SERVER "chat_server"
#define USER_LIST_PREFIX "user_list_"




statusServe_rpc::statusServe_rpc()
{

    //对应子服务的信息不要写死在配置文件里，各个服务启动后，通过grpc向本服务注册/在结束后，通过grpc向本服务注销

    // conf_reader *reader=conf_reader::get_conf_reader_instance();
    // struct chat_server_address *server_1=new struct chat_server_address();
    // server_1->host=std::atoi(reader->get_value_from_key("chat_server_host_1","192.168.174.139"));
    // server_1->port=std::atoi(reader->get_value_from_key("chat_server_port_1","12345"));

    // struct chat_server_address *server_2=new struct chat_server_address();
    // server_2->host=std::atoi(reader->get_value_from_key("chat_server_host_2","192.168.174.139"));
    // server_2->port=std::atoi(reader->get_value_from_key("chat_server_port_2","12346"));

    // this->chat_server_list.push_back(server_1);
    // this->chat_server_list.push_back(server_2);

    //初始化chat_server;从chat_server中找到对应的聊天服务器的信息。并存入


   
    //创建一个心跳检测线程
    this->check_heart_thread=std::thread([this](){
        std::cout<<"心跳检测线程开始了"<<std::endl;
        while(1){
           std::this_thread::sleep_for(std::chrono::seconds(CHECK_HEART_THREAD_GAP));
            //开始检测

            bool flag=false;
            MyRedis *one=redis_pool::get_instance()->get_one_redis();
            if(one!=nullptr){
                flag=true;
            }

            this->s_mtx.lock();
            
            
            std::time_t now_time=time(NULL);

            for(auto it=this->working_chat_server_list.begin();it!=this->working_chat_server_list.end();){

                if((*it)->last_heart_beat+150<now_time){
                   //表示超时了----客户端每隔2min会发送心跳包
                   if(flag){
                    one->del_key((*it)->user_set.c_str());
                   }
                   std::cout<<"chat_server超时："<<now_time-((*it)->last_heart_beat)<<" s"<<std::endl;
                   delete (*it);
                   it=this->working_chat_server_list.erase(it);
                }else{
                    ++it;
                }
            }

            this->s_mtx.unlock();
            redis_pool::get_instance()->give_back_one_redis(one);

        }



    });
    this->check_heart_thread.detach();
    



}




chat_server_address *statusServe_rpc::get_fit_chat_server()
{
    chat_server_address *res=nullptr;
    MyRedis *one=redis_pool::get_instance()->get_one_redis();
    if(one==nullptr){
        return nullptr;
    }

    int min=-1;
    s_mtx.lock_shared();
    for(auto it=working_chat_server_list.begin();it!=working_chat_server_list.end();++it){
        if(res==nullptr){
            res=*it;
            min=one->hget(CHAT_SERVER,(*it)->chat_server_name.c_str());
            if(min==-1){
                perror("在负载均衡时，查询每个chat_server的数值时返回-1 ！！！");
                res=nullptr;
                break;
            }
        }else{
            int tmp=one->hget(CHAT_SERVER,(*it)->chat_server_name.c_str());
            if(tmp==-1){
                perror("在负载均衡时，查询每个chat_server的数值时返回-1 ！！！");
                res=nullptr;
                break;
            }
            if(tmp<min){
                res=*it;
            }
        }
    }
    s_mtx.unlock_shared();

    redis_pool::get_instance()->give_back_one_redis(one);
   
    return  res;
}

std::string statusServe_rpc::get_uuid()
{
    boost::uuids::uuid uuid=boost::uuids::random_generator()();
   
    return boost::uuids::to_string(uuid);
}

void statusServe_rpc::add_chat_server(chat_server_address *new_chat){
    s_mtx.lock();
    working_chat_server_list.push_back(new_chat);
    s_mtx.unlock();


}



void statusServe_rpc::delete_chat_server(std::string host,std::string port){

    int flag=false;
    MyRedis *one=redis_pool::get_instance()->get_one_redis();
    if(one!=nullptr){
        flag=true;
    }

    s_mtx.lock();

    for(auto it=working_chat_server_list.begin();it!=working_chat_server_list.end();){
        if((*it)->host==host&& (*it)->port==port){
            if(flag){
                one->del_key((*it)->user_set.c_str());
            }
            
            delete (*it);
            it=working_chat_server_list.erase(it);
            break;
        }else{
            ++it;
        }
    }

    s_mtx.unlock();

    redis_pool::get_instance()->give_back_one_redis(one);

}



statusServe_rpc::~statusServe_rpc(){
    while(!working_chat_server_list.empty()){
        auto it=working_chat_server_list.front();
        delete (it);
        working_chat_server_list.pop_front();
    }
    std::cout<<"statusServe_rpc服务被delete掉"<<std::endl;
}



//各种服务-------------------------------
::grpc::Status statusServe_rpc::get_chatServer_address(::grpc::ServerContext* context, const ::message::reqGetChatServerAddress* request, ::message::resGetChatServerAddress* response){
    
    chat_server_address *tar=get_fit_chat_server();
    if(tar==nullptr){
        std::cout<<"当前没有可用的chat_server服务！！"<<std::endl;
        response->set_result(false);
        response->set_info("当前没有可用的服务！！");
        return grpc::Status::OK;
    }
    response->set_host(tar->host);
    response->set_port(tar->port);
    response->set_result(true);
    response->set_info("成功返还一个可用的chat服务");
    std::string token=get_uuid();
    
    response->set_token(token);
    if(token_map.count(request->email())){
        token_map[request->email()]=token;  //进行一个替换
    }else{
        token_map.insert(std::make_pair(request->email(),token));
    }
    
    //token写入到redis中---暂时不该


    
    return grpc::Status::OK;

}

::grpc::Status statusServe_rpc::registerChat(::grpc::ServerContext* context, const ::message::reqRegisterChat* request, ::message::resRegisterChat* response){
   

    MyRedis *one=redis_pool::get_instance()->get_one_redis();
    if(one==nullptr){
        response->set_result(false);
        return grpc::Status::OK;
    }
    //设置chat_server的field
    std::string ip_port=request->host()+":"+request->port();
    if(one->hset(CHAT_SERVER,ip_port.c_str(),"0")==-1){
        redis_pool::get_instance()->give_back_one_redis(one);
        response->set_result(false);
        return grpc::Status::OK;
    }
    //重置每个chat_server对应的用户列表

    std::string user_set=USER_LIST_PREFIX+ip_port;
    one->del_key(user_set.c_str());    //可能存在也可能不存在-所以不判断结果

    //用set类型存储吧 key:old_user_set value接一系列的用户email
    

    //如果这里还有上次由于宕机，残留得到相关信息，那么应该直接覆盖，而不是创建一个新的

    s_mtx.lock();

    auto item=check_host_port(request->host(),request->port()); //
    if(item==nullptr){
        chat_server_address *new_chat_server=new chat_server_address();
        new_chat_server->host=request->host();
        new_chat_server->port=request->port();
        new_chat_server->user_set=user_set;
        new_chat_server->chat_server_name=ip_port;
        new_chat_server->last_heart_beat=time(NULL);
        new_chat_server->rpc_server_info=request->rpc_server_info();
        //加进去
        working_chat_server_list.push_back(new_chat_server);
    }

    s_mtx.unlock();


    
    
    redis_pool::get_instance()->give_back_one_redis(one);
    std::cout<<"成功发现一个chat_server服务其ip:"<<request->host()<<" 端口："<<request->port()<<std::endl;


    response->set_result(true);  
    return grpc::Status::OK;
}


::grpc::Status statusServe_rpc::checkToken(::grpc::ServerContext* context, const ::message::reqCheckToken* request, ::message::resCheckToken* response){
    if(this->token_map.count(request->email())==false){
        response->set_result(false);
        return grpc::Status::OK;
    }
    if(token_map[request->email()]!=request->token()){
        response->set_result(false);
        return grpc::Status::OK;
    }
    response->set_result(true);
    return grpc::Status::OK;
    
}


chat_server_address * statusServe_rpc::check_host_port(const std::string host,const std::string port){

    chat_server_address *res=nullptr;

    //s_mtx.lock();   //这个锁由外部去加

    for(auto it=working_chat_server_list.begin();it!=working_chat_server_list.end();++it){
        if((*it)->host==host&& (*it)->port==port){
            (*it)->last_heart_beat=time(NULL);
            res=(*it);
            return res;
        }
    }
    //s_mtx.unlock();

    return res;

}

::grpc::Status statusServe_rpc::deleteChat(::grpc::ServerContext* context, const ::message::reqDeleteChat* request, ::message::resDeleteChat* response){
    std::cout<<"chat_server："<<request->host()<<":"<<request->port()<<"即将下线"<<std::endl;
    this->delete_chat_server(request->host(),request->port());
    return grpc::Status::OK;
}

::grpc::Status statusServe_rpc::heartBeat(::grpc::ServerContext* context, const ::message::reqHeartBeat* request, ::message::resHeartBeat* response){
    std::cout<<"chat_server："<<request->host()<<":"<<request->port()<<"发送心跳包"<<std::endl;
    //找到并更改时间
    chat_server_address *res=nullptr;
    bool flag=false;
    s_mtx.lock();   //这个锁由外部去加

    for(auto it=working_chat_server_list.begin();it!=working_chat_server_list.end();++it){
        if((*it)->host==request->host()&& (*it)->port==request->port()){
            (*it)->last_heart_beat=time(NULL);
            response->set_nothing(true);
            flag=true;

            break;
        }
    }

    //如果没找到，那么就去添加一下
    if(!flag){
        std::string ip_port=request->host()+":"+request->port();
        std::string user_set=USER_LIST_PREFIX+ip_port;
        chat_server_address *new_chat_server=new chat_server_address();
        new_chat_server->host=request->host();
        new_chat_server->port=request->port();
        new_chat_server->user_set=user_set;
        new_chat_server->chat_server_name=ip_port;
        new_chat_server->last_heart_beat=time(NULL);
        new_chat_server->rpc_server_info=request->rpc_server_info();
        //加进去
        working_chat_server_list.push_back(new_chat_server);
        std::cout<<"成功通过心跳发现一个chat_server: "<<ip_port<<std::endl;
        response->set_nothing(true);

    }

    s_mtx.unlock();

    return grpc::Status::OK;
    

}

::grpc::Status statusServe_rpc::getForwardTarget(::grpc::ServerContext* context, const ::message::reqGetForwardTarget* request, ::message::resGetForwardTarget* response){
    
    const std::string& tar=request->email();
    response->set_result(false);    //设置一个默认值
    MyRedis *one=redis_pool::get_instance()->get_one_redis();
    if(one==nullptr){
        std::cout<<"获取redis实例用于获取目标tar时获取失败"<<std::endl;
       
        return grpc::Status::OK;
    }
    
    s_mtx.lock_shared();
    
    for(auto it=working_chat_server_list.begin();it!=working_chat_server_list.end();++it){
        //去所连接的服务器里找，对应的用户，找到返其对应的rpcserver
       if(one->sismember((*it)->user_set.c_str(),tar.c_str())==1){
            response->set_ip_port((*it)->rpc_server_info);
            response->set_result(true);
            break;
       }
    }

    s_mtx.unlock_shared();
    redis_pool::get_instance()->give_back_one_redis(one);
    return grpc::Status::OK;

}

